<template>
  <div class="pdf-container">
    <div class="pdf-view">
      <div class="pdf-wrapper" v-for="item in pdfState.pageCount">
        <canvas :key="item" ref="canvasRefs"></canvas>
        <div v-if="pdfState.pageRendered" class="page">
          {{ item }} / {{ pdfState.pageCount }}
        </div>
      </div>
    </div>
    <!-- <div>
      <span
        >Page: <span id="page_num">{{ pdfState.pageNum }}</span> /
        <span id="page_count">{{ pdfState.pageCount }}</span></span
      >
      <button @click="handleLoadPdf">load</button>
      <button ref="preRef">上一页</button>
      <button ref="nextRef">下一页</button>
    </div> -->
  </div>
</template>

<script setup lang="ts">
import { GlobalWorkerOptions } from "pdfjs-dist";
import * as pdfWorker from "pdfjs-dist/build/pdf.worker.mjs";
import { nextTick, onBeforeUnmount, onMounted, reactive, ref } from "vue";
GlobalWorkerOptions.workerSrc = pdfWorker;

const canvasRefs = ref<Array<HTMLCanvasElement | null>>([]);
const url =
  // "https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf";
  "http://storage.xuetangx.com/public_assets/xuetangx/PDF/PlayerAPI_v1.0.6.pdf";

const { pdfjsLib } = globalThis as any;

// 此处为正确写法---原来我的参数用的响应式写法，就会报错Cannot read from private field
let pdfDoc: any = ""; // 文档内容---必须使用非响应式存储
let pdfState = reactive({
  pageNum: 1,
  pageRendering: false,
  pageNumPending: null,
  scale: 1,
  pageCount: 1,
  pageRendered: false,
});
const updatePdf = ref(false);
const preRef = ref<HTMLButtonElement | null>(null);
const nextRef = ref<HTMLButtonElement | null>(null);

onMounted(() => {
  nextTick(() => {
    initPdf();

    preRef.value?.addEventListener("click", onPrevPage);
    nextRef.value?.addEventListener("click", onNextPage);
  });

  window.addEventListener("resize", handleResize);
});

onBeforeUnmount(() => {
  window.removeEventListener("resize", handleResize);
  preRef.value?.removeEventListener("click", onPrevPage);
  nextRef.value?.removeEventListener("click", onNextPage);
});

const handleResize = async () => {
  await pdfDoc?.destroy();
  pdfState = {
    pageNum: 1,
    pageRendering: false,
    pageNumPending: null,
    scale: 1,
    pageCount: 1,
    pageRendered: false,
  };
  initPdf();
};

/**
 * Asynchronously downloads PDF.
 */
const initPdf = () => {
  console.log("pdfjsLib==", pdfjsLib);

  pdfjsLib.getDocument(url).promise.then((pdfDoc_: any) => {
    console.log("file: Pdf.vue:111 ~ pdfjsLib.getDocument ~ pdfDoc_:", pdfDoc_);
    pdfDoc = pdfDoc_;
    pdfState.pageCount = pdfDoc.numPages;
    // Initial/first page rendering
    renderPage(pdfState.pageNum);
  });
};

/**
 * Get page info from document, resize canvas accordingly, and render page.
 * @param num Page number.
 */
function renderPage(num: number) {
  pdfState.pageRendering = true;
  // Using promise to fetch the page
  pdfDoc.getPage(num).then((page) => {
    console.log("page==", page);
    const viewport = page.getViewport({ scale: pdfState.scale });
    // 40 padding
    const widthScale = document.body.clientWidth / viewport.width;
    const heightScale = document.body.clientHeight / viewport.height;
    const scaledViewport = page.getViewport({ scale: widthScale });
    const ctx = canvasRefs.value[num - 1].getContext("2d");
    let dpr = window.devicePixelRatio || 1;
    // let bsr =
    //   ctx.webkitBackingStorePixelRatio ||
    //   ctx.mozBackingStorePixelRatio ||
    //   ctx.msBackingStorePixelRatio ||
    //   ctx.oBackingStorePixelRatio ||
    //   ctx.backingStorePixelRatio ||
    //   1;
    // let ratio = dpr / bsr;
    canvasRefs.value[num - 1].width = Math.floor(
      viewport.width * widthScale * dpr - 40
    );
    canvasRefs.value[num - 1].height = Math.floor(
      viewport.height * heightScale * dpr - 40
    );
    canvasRefs.value[num - 1].style.width =
      Math.floor(viewport.width * widthScale - 40) + "px";
    canvasRefs.value[num - 1].style.height =
      Math.floor(viewport.height * heightScale - 40) + "px";

    const transform = dpr !== 1 ? [dpr, 0, 0, dpr, 0, 0] : null;
    // canvasRefs.value[num - 1].width = viewport.width * ratio;
    // canvasRefs.value[num - 1].height = viewport.height * ratio;
    // ctx.setTransform(ratio, 0, 0, ratio, 0, 0);

    console.log("viewport=", viewport, canvasRefs.value[num - 1]);

    // Render PDF page into canvas context
    const renderContext = {
      canvasContext: ctx,
      transform: transform,
      viewport: scaledViewport,
      pageColors: {
        color: "#f00",
      },
    };
    const renderTask = page.render(renderContext);

    // Wait for rendering to finish
    renderTask.promise.then(function () {
      pdfState.pageRendering = false;
      if (pdfState.pageNumPending !== null) {
        // New page rendering is pending
        renderPage(pdfState.pageNumPending);
        pdfState.pageNumPending = null;
      }
    });
    pdfState.pageRendered = pdfState.pageCount === num;
    if (pdfState.pageCount > num) {
      renderPage(num + 1);
    }
  });

  // Update page counters
  pdfState.pageNum = num;
}

/**
 * If another page rendering in progress, waits until the rendering is
 * finised. Otherwise, executes rendering immediately.
 */
function queueRenderPage(num: number) {
  if (pdfState.pageRendering) {
    pdfState.pageNumPending = num;
  } else {
    renderPage(num);
  }
}

/**
 * Displays previous page.
 */
function onPrevPage() {
  if (pdfState.pageNum <= 1) {
    return;
  }
  pdfState.pageNum--;
  queueRenderPage(pdfState.pageNum);
}

/**
 * Displays next page.
 */
function onNextPage() {
  if (pdfState.pageNum >= pdfDoc.numPages) {
    return;
  }
  pdfState.pageNum++;
  queueRenderPage(pdfState.pageNum);
}
</script>

<style lang="scss" scoped>
.pdf-container,
.pdf-view {
  width: 100%;
  height: 100%;
  overflow-x: hidden;
}

.pdf-view {
  background-color: #d9e6fb;
  padding: 20px;

  .pdf-wrapper {
    position: relative;
    margin-bottom: 20px;

    &:last-child {
      margin-bottom: 0;
    }

    .page {
      position: absolute;
      bottom: -14px;
      left: 50%;
      transform: translateX(-50%);
      font-size: 12px;
    }
  }
}
</style>
